package com.zhijian.medical.util;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @Description 加解密工具类
 * @Author chengqing
 * @Date 2019年4月14日 下午3:20:45
 * @Version 1.0.1
 */
public class EncryptUtil {
    private final static Logger logger = LoggerFactory.getLogger(EncryptUtil.class);
    private final static String ALGORITHM_MD5 = "MD5";
    private static final String ALGORITHM_CIPHER = "DES/ECB/PKCS5Padding";
    private final static String CHARSET_UTF8 = "UTF-8";
    private static char[] hex = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};


    /**
     * 生成md5摘要
     *
     * @param bytes
     * @return MD5摘要（16进制字符串）
     */
    public static String md5(String message) {
        byte[] bytes = md5Byte(message);
        return new String(Hex.encodeHex(bytes));
    }

    /**
     * 生成md5摘要
     *
     * @param message
     * @return 字节数组，byte[]
     */
    public static byte[] md5Byte(String message) {
        byte[] bytes = null;
        try {
            MessageDigest digest = MessageDigest.getInstance(ALGORITHM_MD5);
            digest.reset();
            bytes = digest.digest(message.getBytes(CHARSET_UTF8));
        } catch (NoSuchAlgorithmException | UnsupportedEncodingException ex) {
            logger.error("md5| digest error,message={}", message, ex);
        }
        return bytes;
    }

    /**
     * byte数组MD5摘要
     *
     * @param message 字节数组
     * @return MD5摘要（16进制字符串）
     */
    public static String md5(byte[] message) {
        if (message == null || message.length < 0) {
            logger.error("md5| error param, message is null");
            return null;
        }
        try {
            MessageDigest digest = MessageDigest.getInstance(ALGORITHM_MD5);
            byte[] bytes = digest.digest(message);
            return new String(Hex.encodeHex(bytes));
        } catch (NoSuchAlgorithmException ex) {
            logger.error("md5| digest error,message={}", message, ex);
        }
        return null;
    }

    /**
     * @return: salt
     * @params:
     * @Descrption: 自定义简单生成盐，是一个随机生成的长度为16的字符串，每一个字符是随机的十六进制字符
     */
    public static String salt() {
        Random random = new Random();
        StringBuilder sb = new StringBuilder(16);
        for (int i = 0; i < sb.capacity(); i++) {
            sb.append(hex[random.nextInt(16)]);
        }
        return sb.toString();
    }

    /**
     * 密码拆分加密
     *
     * @param password
     * @param salt
     * @return
     */
    public static String password(String password, String salt) {
        if (StringUtils.isBlank(password)) {
            return password;
        }
        if (StringUtils.isBlank(salt) || salt.length() < 16) {
            password = String.format("%s_%s", password, salt);
        } else {
            //16位盐拆分两部分
            password = String.format("%s%s_%s", salt.substring(0, 6), password, salt.substring(6));
        }
        return md5(password);
    }

    /**
     * 生成n位数字随机数，返回字符串格式
     *
     * @param n
     * @return
     */
    public static String randomInt(Integer n) {
        if (n == null) {
            n = 5;
        }
        int weight = 1;
        for (int i = 0; i < n; i++) {
            weight = weight * 10;
        }
        return (int) ((Math.random() * 9 + 1) * weight) + "";
    }

    /**
     * 字符串去除特殊字符，如?&=:#等
     *
     * @param content
     * @return
     */
    public static String dislodge(String content) {
        //可以在中括号内加上任何想要替换的字符
        String regEx = "[:/\\.&\\?:=]";
        //这里是将特殊字符换为此字符串,""代表直接去掉
        String replaceContent = "";
        Pattern p = Pattern.compile(regEx);
        //这里把想要替换的字符串传进来
        Matcher m = p.matcher(content);
        return m.replaceAll(replaceContent).trim();
    }


    /**
     * 加密数据
     *
     * @param data      待加密数据
     * @param key       密钥
     * @param algorithm 加密算法
     * @return 加密后的数据
     */
    public static String encrypt(String data, String key, String algorithm) throws Exception {
        Key k = toKey(Base64.decodeBase64(key), algorithm);
        Cipher cipher = Cipher.getInstance(ALGORITHM_CIPHER);
        cipher.init(Cipher.ENCRYPT_MODE, k);
        byte[] encryptData = cipher.doFinal(data.getBytes());
        return Base64.encodeBase64String(encryptData);
    }

    /**
     * 解密数据
     *
     * @param data      待解密数据
     * @param key       密钥
     * @param algorithm 加密算法
     * @return 解密后的数据
     */
    public static String decrypt(String data, String key, String algorithm) throws Exception {
        Key k = toKey(Base64.decodeBase64(key), algorithm);
        Cipher cipher = Cipher.getInstance(ALGORITHM_CIPHER);
        cipher.init(Cipher.DECRYPT_MODE, k);
        return new String(cipher.doFinal(Base64.decodeBase64(data)));
    }

    /**
     * 生成密钥
     */
    private static SecretKey toKey(byte[] key, String algorithm) throws Exception {
        DESKeySpec keySpec = new DESKeySpec(key);
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algorithm);
        return keyFactory.generateSecret(keySpec);
    }
}
